package com.smartum.mpr.business;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.smartum.mpr.dao.UploadedImageClassyDao;
import com.smartum.mpr.dao.UploadedImageCommentDao;
import com.smartum.mpr.dao.UploadedImageDao;
import com.smartum.mpr.dao.UploadedImageGangsterDao;
import com.smartum.mpr.dao.UploadedImageHoaxDao;
import com.smartum.mpr.dao.UploadedImageLikeDao;
import com.smartum.mpr.dao.UploadedImageOddDao;
import com.smartum.mpr.dao.UploadedImageSadDao;
import com.smartum.mpr.dao.UploadedImageSexyDao;
import com.smartum.mpr.dao.UploadedImageTypeDao;
import com.smartum.mpr.dao.UserDao;
import com.smartum.mpr.exception.AlreadyClassyException;
import com.smartum.mpr.exception.AlreadyGangsterException;
import com.smartum.mpr.exception.AlreadyHoaxException;
import com.smartum.mpr.exception.AlreadyLikedException;
import com.smartum.mpr.exception.AlreadyOddException;
import com.smartum.mpr.exception.AlreadySadException;
import com.smartum.mpr.exception.AlreadySexyException;
import com.smartum.mpr.exception.AlreadyTypeException;
import com.smartum.mpr.exception.DatabaseIntegrityException;
import com.smartum.mpr.exception.NotExistsClassyException;
import com.smartum.mpr.exception.NotExistsGangsterException;
import com.smartum.mpr.exception.NotExistsHoaxException;
import com.smartum.mpr.exception.NotExistsImageException;
import com.smartum.mpr.exception.NotExistsLikeException;
import com.smartum.mpr.exception.NotExistsOddException;
import com.smartum.mpr.exception.NotExistsSadException;
import com.smartum.mpr.exception.NotExistsSexyException;
import com.smartum.mpr.exception.NotExistsTokenException;
import com.smartum.mpr.exception.NotExistsTypeException;
import com.smartum.mpr.model.Classy;
import com.smartum.mpr.model.Gangster;
import com.smartum.mpr.model.Hoax;
import com.smartum.mpr.model.Like;
import com.smartum.mpr.model.Odd;
import com.smartum.mpr.model.Sad;
import com.smartum.mpr.model.Sexy;
import com.smartum.mpr.model.Type;
import com.smartum.mpr.model.UploadedImage;
import com.smartum.mpr.model.UploadedImageClassy;
import com.smartum.mpr.model.UploadedImageComment;
import com.smartum.mpr.model.UploadedImageGangster;
import com.smartum.mpr.model.UploadedImageHoax;
import com.smartum.mpr.model.UploadedImageLike;
import com.smartum.mpr.model.UploadedImageOdd;
import com.smartum.mpr.model.UploadedImageSad;
import com.smartum.mpr.model.UploadedImageSexy;
import com.smartum.mpr.model.UploadedImageStatus;
import com.smartum.mpr.model.UploadedImageType;
import com.smartum.mpr.model.User;
import com.smartum.mpr.util.BackendConfig;

@Service
public class UploadedImageBusiness {

	@Autowired
	UserDao userDao;

	@Autowired
	UploadedImageDao imageDao;

	@Autowired
	UploadedImageCommentDao commentDao;

	// Like
	@Autowired
	UploadedImageLikeDao likeDao;

	// Sexy
	@Autowired
	UploadedImageSexyDao sexyDao;

	// Artistic
	@Autowired
	UploadedImageClassyDao classyDao;

	// Odd
	@Autowired
	UploadedImageOddDao oddDao;

	// Hoax
	@Autowired
	UploadedImageHoaxDao hoaxDao;

	// Gangster
	@Autowired
	UploadedImageGangsterDao gangsterDao;

	// Type
	@Autowired
	UploadedImageTypeDao typeDao;

	// Sad
	@Autowired
	UploadedImageSadDao sadDao;

	// Like
	// ************************************
	public void addLikeForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadyLikedException {
		User user = userDao.findUserByToken(token);
		UploadedImage image = imageDao.get(photoID);

		for (UploadedImageLike like : image.getLikes()) {
			if (like.getUser().getId().equals(user.getId())) {
				throw new AlreadyLikedException("photo with id: " + photoID);
			}
		}

		UploadedImageLike like = new UploadedImageLike();
		like.setUser(user);
		like.setImage(image);

		likeDao.save(like);

		Set<UploadedImageLike> likes = image.getLikes();
		likes.add(like);

		imageDao.save(image);

	}

	public void deleteLikeForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadyLikedException, NotExistsLikeException {
		User user = userDao.findUserByToken(token);
		Like like = likeDao.getLike(user.getId(), photoID);
		likeDao.delete(like.getId());
	}

	// Sexy
	// **************************************
	public void addSexyForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadySexyException {
		User user = userDao.findUserByToken(token);
		UploadedImage image = imageDao.get(photoID);

		for (UploadedImageSexy sexy : image.getSexys()) {
			if (sexy.getUser().getId().equals(user.getId())) {
				throw new AlreadySexyException("photo with id: " + photoID);
			}
		}

		UploadedImageSexy sexy = new UploadedImageSexy();
		sexy.setUser(user);
		sexy.setImage(image);

		sexyDao.save(sexy);

		Set<UploadedImageSexy> sexys = image.getSexys();
		sexys.add(sexy);
		imageDao.save(image);

	}

	public void deleteSexyForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadySexyException, NotExistsSexyException {
		User user = userDao.findUserByToken(token);
		Sexy sexy = sexyDao.getSexy(user.getId(), photoID);
		sexyDao.delete(sexy.getId());
	}

	// Classy
	// **************************************
	public void addClassyForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadyClassyException{
		User user = userDao.findUserByToken(token);
		UploadedImage image = imageDao.get(photoID);

		for (UploadedImageClassy classy : image.getClassys()) {
			if (classy.getUser().getId().equals(user.getId())) {
				throw new AlreadyClassyException("photo with id: " + photoID);
			}
		}

		UploadedImageClassy classy = new UploadedImageClassy();
		classy.setUser(user);
		classy.setImage(image);

		classyDao.save(classy);

		Set<UploadedImageClassy> Classys = image.getClassys();
		Classys.add(classy);
		imageDao.save(image);
	}

	public void deleteClassyForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadyClassyException, NotExistsClassyException {
		User user = userDao.findUserByToken(token);
		Classy classy = classyDao.getClassy(user.getId(), photoID);
		classyDao.delete(classy.getId());
	}

	// Gangster
	// **************************************
	public void addGangsterForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadyGangsterException{
		User user = userDao.findUserByToken(token);
		UploadedImage image = imageDao.get(photoID);

		for (UploadedImageGangster gangster : image.getGangsters()) {
			if (gangster.getUser().getId().equals(user.getId())) {
				throw new AlreadyGangsterException("photo with id: " + photoID);
			}
		}

		UploadedImageGangster gangster = new UploadedImageGangster();
		gangster.setUser(user);
		gangster.setImage(image);

		gangsterDao.save(gangster);

		Set<UploadedImageGangster> gangsters = image.getGangsters();
		gangsters.add(gangster);
		imageDao.save(image);
	}

	public void deleteGangsterForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadyGangsterException, NotExistsGangsterException {
		User user = userDao.findUserByToken(token);
		Gangster gangster = gangsterDao.getGangster(user.getId(), photoID);
		gangsterDao.delete(gangster.getId());
	}

	// Odd
	// **************************************
	public void addOddForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadyOddException{
		User user = userDao.findUserByToken(token);
		UploadedImage image = imageDao.get(photoID);

		for (UploadedImageOdd odd : image.getOdds()) {
			if (odd.getUser().getId().equals(user.getId())) {
				throw new AlreadyOddException("photo with id: " + photoID);
			}
		}

		UploadedImageOdd odd = new UploadedImageOdd();
		odd.setUser(user);
		odd.setImage(image);

		oddDao.save(odd);

		Set<UploadedImageOdd> odds = image.getOdds();
		odds.add(odd);
		imageDao.save(image);
	}

	public void deleteOddForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadyOddException, NotExistsOddException {
		User user = userDao.findUserByToken(token);
		Odd odd = oddDao.getOdd(user.getId(), photoID);
		oddDao.delete(odd.getId());
	}

	// Hoax
	// **************************************
	public void addHoaxForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadyHoaxException{
		try {
			User user = userDao.findUserByToken(token);
			UploadedImage image = imageDao.get(photoID);

			for (UploadedImageHoax hoax : image.getHoaxs()) {
				if (hoax.getUser().getId().equals(user.getId())) {
					System.out.println("Samira error 1 "+ hoax.getUser().getId()+ " and " + user.getId() + " token : " +token);
					throw new AlreadyHoaxException("photo with id: " + photoID);
				}
			}

			UploadedImageHoax hoax = new UploadedImageHoax();
			hoax.setUser(user);
			hoax.setImage(image);

			hoaxDao.save(hoax);

			Set<UploadedImageHoax> hoaxs = image.getHoaxs();
			hoaxs.add(hoax);
			imageDao.save(image);
		} catch (Exception e) {
			System.out.println("Error in addHoaxForPhoto : " +e.toString());
			e.printStackTrace();
		}
	}

	public void deleteHoaxForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadyHoaxException, NotExistsHoaxException {
		User user = userDao.findUserByToken(token);
		Hoax hoax = hoaxDao.getHoax(user.getId(), photoID);
		hoaxDao.delete(hoax.getId());
	}
	// Type
	// **************************************
	public void addTypeForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadyTypeException{
		User user = userDao.findUserByToken(token);
		UploadedImage image = imageDao.get(photoID);

		for (UploadedImageType type : image.getTypes()) {
			if (type.getUser().getId().equals(user.getId())) {
				throw new AlreadyTypeException("photo with id: " + photoID);
			}
		}

		UploadedImageType type = new UploadedImageType();
		type.setUser(user);
		type.setImage(image);

		typeDao.save(type);

		Set<UploadedImageType> types = image.getTypes();
		types.add(type);
		imageDao.save(image);
	}

	public void deleteTypeForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadyTypeException, NotExistsTypeException {
		User user = userDao.findUserByToken(token);
		Type type = typeDao.getType(user.getId(), photoID);
		typeDao.delete(type.getId());
	}

	// Sad
	// **************************************
	public void addSadForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadySadException{
		User user = userDao.findUserByToken(token);
		UploadedImage image = imageDao.get(photoID);

		for (UploadedImageSad sad : image.getSads()) {
			if (sad.getUser().getId().equals(user.getId())) {
				throw new AlreadySadException("photo with id: " + photoID);
			}
		}

		UploadedImageSad sad = new UploadedImageSad();
		sad.setUser(user);
		sad.setImage(image);

		sadDao.save(sad);

		Set<UploadedImageSad> sads = image.getSads();
		sads.add(sad);
		imageDao.save(image);
	}

	public void deleteSadForPhoto(String token, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException,
			AlreadySadException, NotExistsSadException {
		User user = userDao.findUserByToken(token);
		Sad sad = sadDao.getSad(user.getId(), photoID);
		sadDao.delete(sad.getId());
	}

	//****************************************
	public void confirmImages(Long[] images) {
		imageDao.confirmImages(images);
	}

	public void declineImages(Long[] images) {
		imageDao.declineImages(images);
	}

	public void addFlagToImage(Long imageId) throws NotExistsImageException {
		UploadedImage image = imageDao.get(imageId);
		if (image == null) {
			throw new NotExistsImageException();
		}

	}

	public UploadedImageComment addCommentForPhoto(String token,
			String commentText, Long photoID)
			throws DatabaseIntegrityException, NotExistsTokenException {
		User user = userDao.findUserByToken(token);
		UploadedImage image = imageDao.get(photoID);
		UploadedImageComment comment = new UploadedImageComment();
		comment.setUser(user);
		comment.setImage(image);
		comment.setCommentText(commentText);

		commentDao.save(comment);

		Set<UploadedImageComment> comments = image.getComments();
		comments.add(comment);

		imageDao.save(image);

		return comment;
	}

	public Long addImage(String token, UploadedImage image)
			throws DatabaseIntegrityException, NotExistsTokenException {
		User user = userDao.findUserByToken(token);
		image.setOwner(user);
		imageDao.save(image);
		return image.getId();
	}

	public List<UploadedImage> getPublicUploadedImages(Long timestamp,
			int amount, Long userId) {
		List<UploadedImage> images = imageDao.getPublicUploadedImages(
				timestamp, amount);
		System.out.println("getPublicUploadedImages debuggin 1");
		for (UploadedImage image : images) {
			System.out.println("getPublicUploadedImages debuggin 2");
			changeImagePathInUploadeImage(image);
			System.out.println("getPublicUploadedImages debuggin 3");
			setLikedStatus(userId, image);
			System.out.println("getPublicUploadedImages debuggin 4");
			System.out.println("getPublicUploadedImages setLikedStatus ok");
			setSexyStatus(userId, image);
			System.out.println("setSexyStatus ok");
			setClassyStatus(userId, image);
			System.out.println("setClassyStatus ok");
			setGangsterStatus(userId, image);
			System.out.println("setGangsterStatus ok");
			setTypedStatus(userId, image);
			System.out.println("setTypedStatus ok");
			setSadStatus(userId, image);
			System.out.println("setSadStatus ok");
			setOddStatus(userId, image);
			System.out.println("setOddStatus ok");
			setHoaxStatus(userId, image);
			System.out.println("setHoaxStatus ok");
			changeImageUrlsIfStatusDeclined(image);
		}
		return images;
	}

	public List<UploadedImage> getUserUploadedImages(Long userId, int amount,
			long timestamp) throws DatabaseIntegrityException,
			NotExistsTokenException {
		List<UploadedImage> images = imageDao.getUserUploadedImages(timestamp,
				amount, userId);
		System.out.println("getUserUploadedImages debuggin 1");
		for (UploadedImage image : images) {
			System.out.println("getUserUploadedImages debuggin 2");
			changeImagePathInUploadeImage(image);
			System.out.println("getUserUploadedImages debuggin 3");
			System.out.println("changeImagePathInUploadeImage ok");
			setLikedStatus(userId, image);
			System.out.println("getUserUploadedImages setLikedStatus ok");
			setSexyStatus(userId, image);
			System.out.println("setSexyStatus ok");
			setClassyStatus(userId, image);
			System.out.println("setClassyStatus ok");
			setGangsterStatus(userId, image);
			System.out.println("setGangsterStatus ok");
			setTypedStatus(userId, image);
			System.out.println("setTypedStatus ok");
			setSadStatus(userId, image);
			System.out.println("setSadStatus ok");
			setOddStatus(userId, image);
			System.out.println("setOddStatus ok");
			setHoaxStatus(userId, image);
			System.out.println("setHoaxStatus ok");
			changeImageUrlsIfStatusDeclined(image);
			System.out.println("changeImageUrlsIfStatusDeclined ok");
		}
		return images;
	}

	public List<UploadedImage> getUnconfirnedImages(long timestamp, int amount) {
		List<UploadedImage> images = imageDao.getUnconfirmedImages(timestamp,
				amount);
		for (UploadedImage image : images) {
			changeImagePathInUploadeImage(image);
		}
		return images;
	}

	public long getUnconfirnedImagesNumber() {
		return imageDao.getUnconfirmedImagesNumber();
	}

	public List<UploadedImageComment> getUploadedImageComments(long photoId)
			throws DatabaseIntegrityException, NotExistsTokenException {
		Set<UploadedImageComment> comments = imageDao.get(photoId)
				.getComments();
		List<UploadedImageComment> commentsList = new ArrayList<UploadedImageComment>();
		commentsList.addAll(comments);
		Collections.sort(commentsList,
				UploadedImageComment.ascendingUploadedImageComparator);
		return commentsList;
	}

	public UploadedImage getUploadedImageById(long photoId)
			throws DatabaseIntegrityException, NotExistsTokenException {
		UploadedImage image = imageDao.get(photoId);
		changeImageUrlsIfStatusDeclined(image);
		return image;
	}

	public void removeImageById(long photoId)
			throws DatabaseIntegrityException, NotExistsTokenException {
		imageDao.delete(photoId);
	}

	public Set<UploadedImageLike> getUploadedImageLikes(long photoId) {
		return imageDao.get(photoId).getLikes();
	}

	public Set<UploadedImageSexy> getUploadedImageSexys(long photoId) {
		return imageDao.get(photoId).getSexys();
	}

	public Set<UploadedImageOdd> getUploadedImageOdds(long photoId) {
		return imageDao.get(photoId).getOdds();
	}

	public Set<UploadedImageType> getUploadedImageTypes(long photoId) {
		return imageDao.get(photoId).getTypes();
	}

	public Set<UploadedImageGangster> getUploadedImageGangster(long photoId) {
		return imageDao.get(photoId).getGangsters();
	}

	public Set<UploadedImageClassy> getUploadedImageClassys(long photoId) {
		return imageDao.get(photoId).getClassys();
	}

	public void updateImageToResponse(UploadedImage image) {
		changeImagePathInUploadeImage(image);
	}

	private void changeImagePathInUploadeImage(UploadedImage image) {
		String appUrl = BackendConfig.getInstance().getAppUrl();
		String imagePath = image.getImagePath();
		image.setImagePath(appUrl + imagePath);
		String littleImagePath = image.getLittleImagePath();
		image.setLittleImagePath(appUrl + littleImagePath);

	}

	private void setLikedStatus(Long userId, UploadedImage image) {
		for (UploadedImageLike like : image.getLikes()) {
			if (like.getUser().getId().equals(userId)) {
				image.setLiked(true);
				return;
			}
		}
		image.setLiked(false);
	}

	private void setSexyStatus(Long userId, UploadedImage image) {
		for (UploadedImageSexy sexy : image.getSexys()) {
			if (sexy.getUser().getId().equals(userId)) {
				image.setSexy(true);
				return;
			}
		}
		image.setSexy(false);
	}

	private void setClassyStatus(Long userId, UploadedImage image) {
		for (UploadedImageClassy artistic : image.getClassys()) {
			if (artistic.getUser().getId().equals(userId)) {
				image.setClassy(true);
				return;
			}
		}
		image.setClassy(false);
	}

	private void setGangsterStatus(Long userId, UploadedImage image) {
		for (UploadedImageGangster gangster : image.getGangsters()) {
			if (gangster.getUser().getId().equals(userId)) {
				image.setGangster(true);
				return;
			}
		}
		image.setGangster(false);
	}

	private void setOddStatus(Long userId, UploadedImage image) {
		for (UploadedImageOdd odd : image.getOdds()) {
			if (odd.getUser().getId().equals(userId)) {
				image.setOdd(true);
				return;
			}
		}
		image.setOdd(false);
	}

	private void setHoaxStatus(Long userId, UploadedImage image) {
		for (UploadedImageHoax hoax : image.getHoaxs()) {
			if (hoax.getUser().getId().equals(userId)) {
				image.setHoax(true);
				return;
			}
		}
		image.setHoax(false);
	}

	private void setTypedStatus(Long userId, UploadedImage image) {
		for (UploadedImageType type : image.getTypes()) {
			if (type.getUser().getId().equals(userId)) {
				image.setTyped(true);
				return;
			}
		}
		image.setTyped(false);
	}

	private void setSadStatus(Long userId, UploadedImage image) {
		for (UploadedImageSad sad : image.getSads()) {
			if (sad.getUser().getId().equals(userId)) {
				image.setSad(true);
				return;
			}
		}
		image.setSad(false);
	}

	private void changeImageUrlsIfStatusDeclined(UploadedImage image) {
		if (image.getStatus() == UploadedImageStatus.DECLINE) {
			String url = BackendConfig.getInstance().getAppUrl()
					+ "-backend/files/decline.png";
			String smallUrl = BackendConfig.getInstance().getAppUrl()
					+ "-backend/files/decline-small.png";

			image.setImagePath(url);
			image.setLittleImagePath(smallUrl);
		}
	}

}
